/*
 * @Author: your name
 * @Date: 2021-09-15 09:34:48
 * @LastEditTime: 2021-09-16 13:45:08
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: \media_system\routes\index.js
 */
const { Sequelize, DataTypes } = require("sequelize");
const moment = require('moment');
const { User, Recipe, RecipeDetail, Food,RecommendRecipe } = require('../database/index')
const Router = require('@koa/router')
const { formatResponse, resizeImg, filterColumn } = require("../utils/common");
const uploadLocal = require('../utils/uploadLocal');
const { uploadQiniu, getFileUrl } = require('../utils/uploadQiNiu');
const router = new Router()
/**
 * @swagger
 *  /recipe/add: #接口访问路径(拼接上之前swagger.js中的host)
 *    post: #请求方式
 *     summary: 添加食谱  #接口信息
 *     description: 添加食谱 #接口描述
 *     tags: [食谱] #接口分组
 *     requestBody:
 *         content:
 *            multipart/form-data:
 *               schema:
 *                  type: object
 *                  required:
 *                  - recipeName
 *                  - type
 *                  - directions
 *                  - avator
 *                  - stars
 *                  - category
 *                  - foods
 *                  properties:
 *                    recipeName:
 *                      type: string
 *                      description: 食谱名称
 *                    category:
 *                      type: integer
 *                      enum: [ "0", "1", "2", "3"]
 *                      description: 就餐类别（0 早餐，1午餐，2晚餐  3加餐）
 *                    type:
 *                      type: integer
 *                      enum: [ "0", "1"]
 *                      description: 类型(0普通 1推荐)
 *                    directions:
 *                      type: string
 *                      description: 制作指南
 *                    avator:          
 *                      type: string
 *                      format: binary
 *                      description: 食物封面照片
 *                    stars:
 *                      type: integer
 *                      description: 推荐指数
 *                    foods:
 *                      type: array
 *                      description: 食物数组
 *                      items:     #$ref: '#/components/schemas/foodModel'
 *                        type: object
 *                        properties:
 *                          foodId:
 *                            type: string
 *                            description: 食物ID
 *                          foodWeight:
 *                            type: number
 *                            description: 食物重量
 *                          foodCount:
 *                            type: number
 *                            description: 食物数量
 *                        example:
 *                          - "foodId": "123111"
 *                            "foodWeight": "150"
 *                            "foodCount": "0"
 *                          - "foodId": "111111"
 *                            "foodWeight": "250"
 *                            "foodCount": "0"
 *     responses: #返回结果
 *       200:
 *         description: 成功

 */
router.post("/add", async function (ctx, next) {
  let err = await uploadLocal.single('avator')(ctx, next)
    .then(res => res)
    .catch(err => err)
  if (err) {
    ctx.body = formatResponse("500", {
      code: 0,
      message: err.message
    }, "fail");
  } else {
    let recipeInfo = ctx.request.body;
    //完成图片logo的缩放和转换成base64
    const data64str = await resizeImg(ctx.file)
    //完成七牛云上传
    try {
      const result = await uploadQiniu(ctx.file).catch((error) => {
        throw error
      })
      recipeInfo = { ...recipeInfo, logoImg: data64str, avator: getFileUrl(result.respBody.key) }

      let cRecipe = await Recipe.create({
        ...recipeInfo,
      });
      //为解决swagger对象变成字符串问题
      if (typeof recipeInfo.foods === 'string') {
        recipeInfo.foods = JSON.parse(recipeInfo.foods)
      }

      let ps = []
      recipeInfo.foods.forEach(async f => {
        const cf = Food.build({
          foodId: f.foodId
        })
        let p = cRecipe.addFood(cf, { through: { foodWeight: f.foodWeight, foodCount: f.foodCount } })
        ps.push(p)
      })
     //foreach不支持await，因此这里使用promise.all
      res = await Promise.all(ps).then(async () => {
        const result = await cRecipe.reload().then(async (c) => {
          let totalProtein = 0
          let totalFat = 0
          let totalCarbohydrate = 0
          let totalCaloric = 0
          const foods = await c.getFoods()
          foods.forEach((f) => {
            totalProtein += parseFloat(f.protein) * (parseFloat(f.recipeDetail.foodWeight) / 100)
            totalFat += parseFloat(f.fat) * (parseFloat(f.recipeDetail.foodWeight) / 100)
            totalCarbohydrate += parseFloat(f.carbohydrate) * (parseFloat(f.recipeDetail.foodWeight) / 100)
            totalCaloric += parseFloat(f.caloric) * (parseFloat(f.recipeDetail.foodWeight) / 100)
          })
          //更新食谱
          c.set({
            totalProtein: totalProtein.toFixed(2),
            totalFat: totalFat.toFixed(2),
            totalCarbohydrate: totalCarbohydrate.toFixed(2),
            totalCaloric: totalCaloric.toFixed(2)
          });
          return c.save()
        })
        return result
      }).catch((err)=>{
        throw err
      })
      if (cRecipe) {
        ctx.body = formatResponse("200", { ...res.get({ plain: true }) }, "success");
      } else {
        ctx.body = formatResponse("500", "", "fail");
      }
    } catch (error) {
      ctx.body = formatResponse("500", error, "fail");
    }
  }
});

/**
 * @swagger
 *  /recipe/addRecommend: #接口访问路径(拼接上之前swagger.js中的host)
 *    post: #请求方式
 *     summary: 添加推荐食谱信息  #接口信息
 *     description: 添加推荐食谱信息  #接口描述
 *     tags: [食谱] #接口分组
 *     produces:
 *       - application/json
 *     consumes:
 *       - application/json
 *     requestBody:
 *         content:
 *            application/json:
 *               schema:
 *                  type: object
 *                  required:
 *                  - recommendRecipeInfo
 *                  - week
 *                  - category
 *                  - age
 *                  properties:
 *                    recommendRecipeInfo:
 *                      type: string
 *                      description: 推荐食谱信息
 *                    category:
 *                      type: integer
 *                      description: 就餐类别（0 早餐，1午餐，2晚餐）
 *                    week:
 *                      type: integer
 *                      description: 周天（0 概要，1-7 周一到周日）
 *                    age:
 *                      type: integer
 *                      description: 儿童年龄（2-18）
 *     responses: #返回结果
 *       200:
 *         description: 成功
 */
router.post("/addRecommend", async function (ctx, next) {
  let recommendRecipe = ctx.request.body;
  let param = 100
  if(recommendRecipe.age){
    if(recommendRecipe.age<3){
      param = 100
    }else if(recommendRecipe.age>=3&&recommendRecipe.age<=6){
      param = 90
    }else if(recommendRecipe.age>=7&&recommendRecipe.age<=10){
      param = 80
    }else if(recommendRecipe.age>10){
      param = 70
    }
  }
  const cRecommendRecipe = await RecommendRecipe.create({
    recommendRecipeInfo: recommendRecipe.recommendRecipeInfo,
    category: recommendRecipe.category,
    week: recommendRecipe.week,
    age: recommendRecipe.age,
    totalKcal:recommendRecipe.age?(recommendRecipe.age*param+1000):0
  });

  if (cRecommendRecipe) {
    ctx.body = formatResponse("200", { ...cRecommendRecipe.get({ plain: true }) }, "success");
  } else {
    ctx.body = formatResponse("500", "", "fail");
  }
});

/**
 * @swagger
 * /recipe/removeRecommend:
 *   get:
 *     security:
 *       - bearerAuth: []
 *     summary: 删除推荐食谱信息  #接口信息
 *     description: 删除推荐食谱信息  #接口信息
 *     tags: [食谱]
 *     parameters:
 *       - name: recommendRecipeId
 *         in: query #参数存放位置。query是存放到请求头里边
 *         required: true
 *         description: 推荐食谱ID
 *         type: string
 *     responses:
 *       200:
 *         description: 成功响应
 */
router.get("/removeRecommend", async function (ctx, next) {
  const { recommendRecipeId } = ctx.request.query;
  const count = await RecommendRecipe.destroy({
    where: {
      recommendRecipeId: recommendRecipeId
    }
  });
  if (count > 0) {
    ctx.body = formatResponse("200", "", "success");
  } else {
    ctx.body = formatResponse("500", "", "fail");
  }
});

/**
 * @swagger
 *  /recipe/updateRecommend: #接口访问路径(拼接上之前swagger.js中的host)
 *    post: #请求方式
 *     summary: 更新推荐食谱信息  #接口信息
 *     description: 更新推荐食谱信息 #接口描述
 *     tags: [食谱] #接口分组
 *     produces:
 *       - application/json
 *     consumes:
 *       - application/json
 *     requestBody:
 *         content:
 *            application/json:
 *               schema:
 *                  type: object
 *                  properties:
 *                    recommendRecipeInfo:
 *                      type: string
 *                      description: 推荐食谱信息
 *                    category:
 *                      type: integer
 *                      description: 就餐类别（0 早餐，1午餐，2晚餐）
 *                    week:
 *                      type: integer
 *                      description: 周天（0 概要，1-7 周一到周日）
 *                    age:
 *                      type: integer
 *                      description: 儿童年龄（2-18）         
 *     responses: #返回结果
 *       200:
 *         description: 成功
 */
router.post("/updateRecommend", async function (ctx, next) {
  let recommendRecipe = ctx.request.body;
  recommendRecipe = filterColumn(recommendRecipe)
  let param = 100
  if(recommendRecipe.age){
    if(recommendRecipe.age<3){
      param = 100
    }else if(recommendRecipe.age>=3&&recommendRecipe.age<=6){
      param = 90
    }else if(recommendRecipe.age>=7&&recommendRecipe.age<=10){
      param = 80
    }else if(recommendRecipe.age>10){
      param = 70
    }
  }
  recommendRecipe.totalKcal = recommendRecipe.age?(recommendRecipe.age*param+1000):0
  let cRecommendRecipe = await RecommendRecipe.findOne({
    where: {
      recommendRecipeId: recommendRecipe.recommendRecipeId,
    },
  });
  cRecommendRecipe = await cRecommendRecipe.update({
    ...recommendRecipe
  })
  if (cRecommendRecipe) {
    ctx.body = formatResponse("200", { ...cRecommendRecipe.get({ plain: true }) }, "success");
  } else {
    ctx.body = formatResponse("500", "", "fail");
  }
});

/**
 * @swagger
 * /recipe/queryRecommend:
 *   get:
 *     security:
 *       - bearerAuth: []
 *     summary: 查询指定条件的推荐食谱信息
 *     description: 查询指定条件的推荐食谱信息
 *     tags: [食谱]
 *     parameters:
 *       - name: category
 *         in: query #参数存放位置。query是存放到请求头里边
 *         required: true
 *         description: 就餐类别（0 早餐，1午餐，2晚餐  3加餐）
 *         type: integer
 *       - name: week
 *         in: query #参数存放位置。query是存放到请求头里边
 *         required: true
 *         description: 周天（0 概要，1-7 周一到周日）
 *         type: number
 *       - name: age
 *         in: query #参数存放位置。query是存放到请求头里边
 *         required: true
 *         description: 儿童年龄（2-18）   
 *         type: number
 *     responses:
 *       200:
 *         description: 成功响应
 */
router.get("/queryRecommend", async function (ctx, next) {
  const { category, week,age } = ctx.request.query;
  const Op = Sequelize.Op;
  const condition1 = category ? { category: { [Op.eq]: category } } : null;
  const condition2 = week ? { week: { [Op.eq]: week } } : null;
  const condition3 = age ? { age: { [Op.eq]: age } } : null;
  let recipes = await RecommendRecipe.findAll({
    where: Object.assign({}, condition1, condition2, condition3),
    order: [['week', 'ASC']],
  });
  if (recipes.length>=0) {
    ctx.body = formatResponse("200", recipes, "success");
  } else{
    ctx.body = formatResponse("500", "", "fail");
  }
});


/**
 * @swagger
 * /recipe/getRecommendRecipe:
 *   get:
 *     security:
 *       - bearerAuth: []
 *     summary: 根据就餐类别查询推荐食谱(指定类型下符合碳水条件的随机10条)
 *     description: 根据就餐类别查询推荐食谱(指定类型下符合碳水条件的随机10条)
 *     tags: [食谱]
 *     parameters:
 *       - name: category
 *         in: query #参数存放位置。query是存放到请求头里边
 *         required: true
 *         description: 就餐类别（0 早餐，1午餐，2晚餐  3加餐）
 *         type: integer
 *       - name: carbohydrate
 *         in: query #参数存放位置。query是存放到请求头里边
 *         required: true
 *         description: 碳水值
 *         type: number
 *     responses:
 *       200:
 *         description: 成功
 */
router.get("/getRecommendRecipe", async function (ctx, next) {
  const { category, carbohydrate } = ctx.request.query;
  const Op = Sequelize.Op;
  let recipes = await Recipe.findAll({
    where: {
      category,
      totalCarbohydrate: { [Op.lt]: carbohydrate }
    },
    order: Sequelize.literal('rand()'), limit: 15,
    // include: {
    //   model: Food,
    //   as: 'foods' //定义belongsToMany的时候要加别名，这里关联的时候要加别名，不然输出的属性名是food而不是foods
    // }
  });
  // console.log(recipes);//findAll返回的数组对象，不需要使用get({ plain: true }
  if (recipes) {
    ctx.body = formatResponse("200", recipes, "success");
  } else {
    ctx.body = formatResponse("500", "", "fail");
  }
});
/**
 * @swagger
 * /recipe/getRecipesByPageAndCondition:
 *   get:
 *     security:
 *       - bearerAuth: []
 *     summary: 条件分页查询食谱
 *     description: 条件分页查询食谱
 *     tags: [食谱]
 *     parameters:
 *       - name: recipeName
 *         in: query #参数存放位置。query是存放到请求头里边
 *         description: 食谱名称
 *         type: string
 *       - name: category
 *         in: query #参数存放位置。query是存放到请求头里边
 *         description: 就餐类别（0 早餐，1午餐，2晚餐  3加餐）
 *         type: integer
 *       - name: type
 *         in: query #参数存放位置。query是存放到请求头里边
 *         description: 类型(0普通 1推荐)
 *         type: integer
 *       - name: stars
 *         in: query #参数存放位置。query是存放到请求头里边
 *         description: 推荐指数（请填写两个参数，表示[x,y]x到y颗心）
 *         schema:
 *          type: array
 *          items:
 *            type: integer
 *       - name: currentPage
 *         in: query #参数存放位置。query是存放到请求头里边
 *         required: true
 *         description: 当前第几页
 *         default: 1
 *         type: string
 *       - name: pageSize
 *         in: query #参数存放位置。query是存放到请求头里边
 *         required: true
 *         default: 5
 *         description: 一页几条记录
 *         type: string
 *     responses:
 *       200:
 *         description: 成功
 */
router.get("/getRecipesByPageAndCondition", async function (ctx, next) {
  const Op = Sequelize.Op;
  const { currentPage, pageSize, recipeName, category, type, stars } = ctx.request.query;
  offset = (currentPage - 1) * pageSize || 0;
  //条件1：食谱名称
  //条件2：就餐类别（0 早餐，1午餐，2晚餐  3加餐）
  //条件3：类型(0普通 1推荐)
  //条件4：推荐指数
  const condition1 = recipeName ? { recipeName: { [Op.like]: `%${recipeName}%` } } : null;
  const condition2 = category ? { category: { [Op.eq]: category } } : null;
  const condition3 = type ? { type: { [Op.eq]: type } } : null;
  const condition4 = stars ? stars.length > 0 ? { 'stars': { [Op.between]: stars } } : null : null;
  let result = await Recipe.findAndCountAll({
    where: Object.assign({}, condition1, condition2, condition3, condition4),
    order: [['createdAt', 'DESC']],
    offset,
    limit: parseInt(pageSize),
  });
  if (result) {
    ctx.body = formatResponse("200", result, "success");
  } else {
    ctx.body = formatResponse("500", "", "fail");
  }
});
/**
 * @swagger
 * /recipe/getRecipeById:
 *   get:
 *     security:
 *       - bearerAuth: []
 *     summary: 根据食谱ID查询食谱详情
 *     description: 根据食谱ID查询食谱详情
 *     tags: [食谱]
 *     parameters:
 *       - name: recipeId
 *         in: query #参数存放位置。query是存放到请求头里边
 *         description: 食谱ID
 *         type: string
 *     responses:
 *       200:
 *         description: 成功
 */
router.get("/getRecipeById", async function (ctx, next) {
  const { recipeId } = ctx.request.query;
  let cRecipe = await Recipe.findOne({
    where: { recipeId },
    include: {
      model: Food,
      as: 'foods' //定义belongsToMany的时候要加别名，这里关联的时候要加别名，不然输出的属性名是food而不是foods
    }
  });
  if (cRecipe) {
    ctx.body = formatResponse("200", cRecipe, "success");
  } else {
    ctx.body = formatResponse("500", "", "fail");
  }
});

/**
 * @swagger
 * /recipe/getAllRecipe:
 *   get:
 *     security:
 *       - bearerAuth: []
 *     summary: 查询所有食谱
 *     description: 查询所有食谱
 *     tags: [食谱]
 *     responses:
 *       200:
 *         description: 成功
 */
router.get("/getAllRecipe", async function (ctx, next) {
  let recipes = await Recipe.findAll();
  if (recipes) {
    ctx.body = formatResponse("200", recipes, "success");
  } else {
    ctx.body = formatResponse("500", "", "fail");
  }
});


/**
 * @swagger
 * /recipe/deleteRecipe:
 *   get:
 *     security:
 *       - bearerAuth: []
 *     summary: 根据食谱ID删除食谱
 *     description: 根据食谱ID删除食谱
 *     tags: [食谱]
 *     parameters:
 *       - name: recipeIds
 *         in: query #参数存放位置。query是存放到请求头里边
 *         required: true
 *         description: 食谱ID
 *         schema:
 *          type: array
 *          items:
 *            type: string
 *     responses:
 *       200:
 *         description: 成功
 */
router.get("/deleteRecipe", async function (ctx, next) {
  const { recipeIds } = ctx.request.query;
  const count = await Recipe.destroy({
    where: {
      recipeId: recipeIds
    }
  });
  if (count > 0) {
    ctx.body = formatResponse("200", "", "success");
  } else {
    ctx.body = formatResponse("500", "", "fail");
  }
});

/**
 * @swagger
 * /recipe/updateRecipe: #接口访问路径(拼接上之前swagger.js中的host)
 *   post: #请求方式
 *     security:
 *       - bearerAuth: []
 *     summary: 根据食谱ID更新食谱信息  #接口信息
 *     description: 根据食谱ID更新食谱信息 #接口描述
 *     tags: [食谱] #接口分组
 *     produces:
 *       - application/json
 *     consumes:
 *       - application/json
 *     requestBody:
 *         content:
 *            multipart/form-data:
 *               schema:
 *                  type: object
 *                  required:
 *                  - recipeId
 *                  properties:
 *                    recipeId:          # <!--- form field name
 *                        type: string
 *                        description: 食谱ID
 *                    recipeName:
 *                      type: string
 *                      description: 食谱名称
 *                    category:
 *                      type: integer
 *                      enum: [ "0", "1", "2", "3"]
 *                      description: 就餐类别（0 早餐，1午餐，2晚餐  3加餐）
 *                    type:
 *                      type: integer
 *                      enum: [ "0", "1"]
 *                      description: 类型(0普通 1推荐)
 *                    directions:
 *                      type: string
 *                      description: 制作指南
 *                    avator:          
 *                      type: string
 *                      format: binary
 *                      description: 食物封面照片
 *                    stars:
 *                      type: integer
 *                      description: 推荐指数
 *                    foods:
 *                      description: 食物数组
 *                      type: array
 *                      items:
 *                        type: object
 *                        properties:
 *                          foodId:
 *                            type: string
 *                            description: 食物ID
 *                          foodWeight:
 *                            type: number
 *                            description: 食物重量
 *                          foodCount:
 *                            type: number
 *                            description: 食物数量
 *                        example:
 *                          - "foodId": "123111"
 *                            "foodWeight": "150"
 *                            "foodCount": "0"
 *                          - "foodId": "111111"
 *                            "foodWeight": "250"
 *                            "foodCount": "0"
 *     responses: #返回结果
 *       200:
 *         description: 成功
 */
router.post("/updateRecipe", async function (ctx, next) {
  let err = await uploadLocal.single('avator')(ctx, next).then(res => res).catch(err => err)
  if (err) {
    ctx.body = formatResponse("500", {
      code: 0,
      message: '上传图片故障' + err.message
    }, "fail");
  } else {
    try {
      let recipeInfo = ctx.request.body;
      recipeInfo = filterColumn(recipeInfo)
      if (ctx.file) {
        //完成图片logo的缩放和转换成base64
        const data64str = await resizeImg(ctx.file)
        //完成七牛云上传
        const result = await uploadQiniu(ctx.file).catch((error) => {
          throw error
        })
        recipeInfo = { ...recipeInfo, logoImg: data64str, avator: getFileUrl(result.respBody.key) }
      }
      let totalProtein = 0
      let totalFat = 0
      let totalCarbohydrate = 0
      let totalCaloric = 0
      if (recipeInfo.hasOwnProperty("foods")) {
        await Recipe.findByPk(recipeInfo.recipeId).then(async function (recipe) {
          let nfoods = []
          //为解决swagger对象变成字符串问题
          if (typeof recipeInfo.foods === 'string') {
            recipeInfo.foods = JSON.parse(recipeInfo.foods)
          }
          recipeInfo.foods.forEach(async f => {
            const cf = Food.build({
              foodId: f.foodId
            })
            cf.recipeDetail = {//此处不能写RecipeDetail，要写recipeDetail，太坑
              foodWeight: f.foodWeight, foodCount: f.foodCount
            }
            nfoods.push(cf)
          })
          
          await recipe.setFoods(nfoods)

        }).then(async () => {
          //计算饮食中所有食物的热量，脂肪，蛋白质等
          const nfoods = await Food.findAll({
            where: {
              foodId: recipeInfo.foods.map((f) => { return f.foodId })
            }
          })
          recipeInfo.foods.forEach((f1) => {
            nfoods.forEach((f2) => {
              if (f1.foodId === f2.foodId) {
                totalProtein += f2.protein * (f1.foodWeight / 100)
                totalFat += f2.fat * (f1.foodWeight / 100)
                totalCarbohydrate += f2.carbohydrate * (f1.foodWeight / 100)
                totalCaloric += f2.caloric * (f1.foodWeight / 100)
              }
            })
          })
        }).catch((err) => {
          ctx.body = formatResponse("500", err, "fail");
        })
      }
      const result = await Recipe.update(
        {
          ...recipeInfo,
          totalProtein: totalProtein.toFixed(2),
          totalFat: totalFat.toFixed(2),
          totalCarbohydrate: totalCarbohydrate.toFixed(2),
          totalCaloric: totalCaloric.toFixed(2)
        },
        {
          where: {
            recipeId: recipeInfo.recipeId,
          },
        }
      )
      if (result[0] > 0) {
        ctx.body = formatResponse("200", { code: 200, message: '食谱更新成功' }, "success");
      } else {
        ctx.body = formatResponse("500", { code: 500, message: '食谱更新失败' }, "fail");
      }
    } catch (error) {
      // console.log(333333333333333333)
      ctx.body = formatResponse("500", error, "fail");
    }
  }
});
module.exports = router